import { type DateLib, defaultDateLib } from "./DateLib.js";

/**
 * Represents a day displayed in the calendar.
 *
 * In DayPicker, a `CalendarDay` is a wrapper around a `Date` object that
 * provides additional information about the day, such as whether it belongs to
 * the displayed month.
 */
export class CalendarDay {
  constructor(
    date: Date,
    displayMonth: Date,
    dateLib: DateLib = defaultDateLib,
  ) {
    this.date = date;
    this.displayMonth = displayMonth;
    this.outside = Boolean(
      displayMonth && !dateLib.isSameMonth(date, displayMonth),
    );
    this.dateLib = dateLib;
    this.isoDate = dateLib.format(date, "yyyy-MM-dd");
    this.displayMonthId = dateLib.format(displayMonth, "yyyy-MM");
    this.dateMonthId = dateLib.format(date, "yyyy-MM");
  }

  /**
   * Utility functions for manipulating dates.
   *
   * @private
   */
  readonly dateLib: DateLib;

  /**
   * Indicates whether the day does not belong to the displayed month.
   *
   * If `outside` is `true`, use `displayMonth` to determine the month to which
   * the day belongs.
   */
  readonly outside: boolean;

  /**
   * The month that is currently displayed in the calendar.
   *
   * This property is useful for determining if the day belongs to the same
   * month as the displayed month, especially when `showOutsideDays` is
   * enabled.
   */
  readonly displayMonth: Date;

  /** The date represented by this day. */
  readonly date: Date;

  /**
   * Stable `yyyy-MM-dd` representation for reuse in keys/data attrs.
   *
   * @since V9.11.2
   */
  readonly isoDate: string;

  /**
   * Stable `yyyy-MM` representation of the displayed month.
   *
   * @since V9.11.2
   */
  readonly displayMonthId: string;

  /**
   * Stable `yyyy-MM` representation of the date's actual month.
   *
   * @since V9.11.2
   */
  readonly dateMonthId: string;

  /**
   * Checks if this day is equal to another `CalendarDay`, considering both the
   * date and the displayed month.
   *
   * @param day The `CalendarDay` to compare with.
   * @returns `true` if the days are equal, otherwise `false`.
   */
  isEqualTo(day: CalendarDay) {
    return (
      this.dateLib.isSameDay(day.date, this.date) &&
      this.dateLib.isSameMonth(day.displayMonth, this.displayMonth)
    );
  }
}
